package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheLoginUser;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStore;
import top.lixunda.ecommerce.server.user.api.entity.db.*;
import top.lixunda.ecommerce.server.user.api.entity.dto.SystemMenuAllotDTO;
import top.lixunda.ecommerce.server.user.mapper.AccountMapper;
import top.lixunda.ecommerce.server.user.mapper.RoleMapper;
import top.lixunda.ecommerce.server.user.mapper.SystemMenuAllotMapper;
import top.lixunda.ecommerce.server.user.mapper.SystemMenuMapper;
import top.lixunda.ecommerce.server.user.service.ISystemMenuAllotService;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单分配表，将存在的菜单分配给用户，角色 服务类 服务实现类
 * </p>
 *
 * @author Lixunda
 * @since 2020-04-24
 */
@Slf4j
@Service
public class SystemMenuAllotServiceImpl
        extends BaseServiceImpl<SystemMenuAllotMapper, SystemMenuAllotDO>
        implements ISystemMenuAllotService {

    private final RoleMapper roleMapper;

    private final AccountMapper accountMapper;

    private final SystemMenuMapper systemMenuMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public SystemMenuAllotServiceImpl(RoleMapper roleMapper,
                                      AccountMapper accountMapper,
                                      SystemMenuMapper systemMenuMapper) {
        this.roleMapper = roleMapper;
        this.accountMapper = accountMapper;
        this.systemMenuMapper = systemMenuMapper;
    }

    /**
     * 分配菜单
     *
     * @param list 菜单操作DTO
     * @return 是否保存成功
     */
    @Override
    public Boolean allotMenu(List<SystemMenuAllotDTO> list) {
        // 添加用户菜单
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("分配用户菜单失败！参数不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        CacheStore cacheStore = null;
        if (cacheLoginUser.getType().equals(BusinessConstants.USER_TYPE_STORE)) {
            cacheStore = currentStoreCacheNotNull();
        }
        int count;
        for (SystemMenuAllotDTO item : list) {
            // 检验分配对象
            switch (item.getAllotPart()) {
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_USER:
                    count = accountMapper.selectCount(new LambdaQueryWrapper<AccountDO>()
                            .eq(AccountDO::getAccount, item.getPartId())
                            .eq(AccountDO::getUserType, cacheLoginUser.getType()));
                    if (count <= 0) {
                        throw getAppException("分配用户菜单失败！用户不存在：" + item.getPartId());
                    }
                    break;
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_ROLE:
                    LambdaQueryWrapper<RoleDO> wrapper = new LambdaQueryWrapper<RoleDO>()
                            .eq(RoleDO::getRoleId, item.getPartId())
                            .eq(RoleDO::getManageType, cacheLoginUser.getType());
                    if (ObjectValidators.isNotEmpty(cacheStore)) {
                        wrapper.eq(RoleDO::getStoreId, cacheStore.getId());
                    }
                    count = roleMapper.selectCount(new LambdaQueryWrapper<RoleDO>()
                            .eq(RoleDO::getRoleId, item.getPartId())
                            .eq(RoleDO::getManageType, cacheLoginUser.getType()));
                    if (count <= 0) {
                        throw getAppException("分配用户菜单失败！角色不存在：" + item.getPartId());
                    }
                    break;
                default:
                    log.debug("不支持的分配对象类型：" + item.getAllotPart());
                    throw getAppException("不支持的分配对象类型：" + item.getAllotPart());
            }
            // 检验菜单存在性
            if (ObjectValidators.isEmpty(item.getMenuIds())) {
                throw getAppException("分配用户菜单失败！菜单列表不能为空！");
            }
            count = systemMenuMapper.selectCount(new LambdaQueryWrapper<SystemMenuDO>()
                    .in(SystemMenuDO::getMenuId, item.getMenuIds())
                    .eq(SystemMenuDO::getUsable, BusinessConstants.USEABLE_TRUE));
            if (count != item.getMenuIds().size()) {
                throw getAppException("分配用户菜单失败！部分菜单不存在！");
            }
        }
        // 创建插入对象
        LocalDateTime localDateTime = LocalDateTime.now();
        List<SystemMenuAllotDO> insert = list.stream()
                .filter(Objects::nonNull)
                .flatMap(item -> item.getMenuIds().stream()
                        .filter(Objects::nonNull)
                        .map(item2 -> new SystemMenuAllotDO()
                                .setPartId(item.getPartId())
                                .setAllotPart(item.getAllotPart())
                                .setMenuId(item2)
                                .setAllotMode(BusinessConstants.ALLOT_MODE_HAND)
                                .setCreateTime(localDateTime)
                                .setCreateUserId(cacheLoginUser.getAccount())
                                .setCreateUserName(cacheLoginUser.getName())
                                .setCreateUserType(cacheLoginUser.getType())))
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(insert)) {
            log.info("分配用户菜单失败！插入数据为空！");
            throw getAppException("分配用户菜单失败！插入数据为空！");
        }
        boolean success = this.saveBatch(insert);
        if (!success) {
            log.info("分配用户菜单失败！插入数据失败！");
            throw getAppException("分配用户菜单失败！插入数据失败！");
        }
        return true;
    }

    /**
     * 移除菜单
     *
     * @param list 菜单操作DTO
     * @return 是否移除成功
     */
    @Override
    public Boolean removeMenuAllot(List<SystemMenuAllotDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除用户菜单失败！参数不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        CacheStore cacheStore = null;
        if (cacheLoginUser.getType().equals(BusinessConstants.USER_TYPE_STORE)) {
            cacheStore = currentStoreCacheNotNull();
        }
        int count;
        for (SystemMenuAllotDTO item : list) {
            // 检验分配对象
            switch (item.getAllotPart()) {
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_USER:
                    count = accountMapper.selectCount(new LambdaQueryWrapper<AccountDO>()
                            .eq(AccountDO::getAccount, item.getPartId())
                            .eq(AccountDO::getUserType, cacheLoginUser.getType()));
                    if (count <= 0) {
                        throw getAppException("移除用户菜单权限失败！用户不存在：" + item.getPartId());
                    }
                    break;
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_ROLE:
                    LambdaQueryWrapper<RoleDO> wrapper = new LambdaQueryWrapper<RoleDO>()
                            .eq(RoleDO::getRoleId, item.getPartId())
                            .eq(RoleDO::getManageType, cacheLoginUser.getType());
                    if (ObjectValidators.isNotEmpty(cacheStore)) {
                        wrapper.eq(RoleDO::getStoreId, cacheStore.getId());
                    }
                    count = roleMapper.selectCount(new LambdaQueryWrapper<RoleDO>()
                            .eq(RoleDO::getRoleId, item.getPartId())
                            .eq(RoleDO::getManageType, cacheLoginUser.getType()));
                    if (count <= 0) {
                        throw getAppException("移除用户菜单失败！角色不存在：" + item.getPartId());
                    }
                    break;
                default:
                    log.debug("不支持的分配对象类型：" + item.getAllotPart());
                    throw getAppException("不支持的分配对象类型：" + item.getAllotPart());
            }
            // 检验菜单存在性
            if (ObjectValidators.isEmpty(item.getMenuIds())) {
                throw getAppException("分配用户菜单失败！菜单列表不能为空！");
            }
            count = systemMenuMapper.selectCount(new LambdaQueryWrapper<SystemMenuDO>()
                    .in(SystemMenuDO::getMenuId, item.getMenuIds())
                    .eq(SystemMenuDO::getUsable, BusinessConstants.USEABLE_TRUE));
            if (count != item.getMenuIds().size()) {
                throw getAppException("移除用户菜单失败！部分菜单不存在！");
            }
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        list.forEach(item -> this.update(new LambdaUpdateWrapper<SystemMenuAllotDO>()
                .set(SystemMenuAllotDO::getRemoveTime, localDateTime)
                .set(SystemMenuAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                .set(SystemMenuAllotDO::getRemoveUserName, cacheLoginUser.getName())
                .set(SystemMenuAllotDO::getRemoveTime, cacheLoginUser.getType())
                .set(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .eq(SystemMenuAllotDO::getPartId, item.getPartId())
                .eq(SystemMenuAllotDO::getAllotPart, item.getAllotPart())
                .eq(SystemMenuAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND)
                .eq(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_TRUE)
                .in(SystemMenuAllotDO::getMenuId, item.getMenuIds())));
        return true;
    }

    /**
     * 根据分配编号移除菜单分配
     *
     * @param list 分配编号列表
     * @return 是否移除成功
     */
    @Override
    public Boolean removeMenuAllotByIds(List<Integer> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除用户菜单失败！参数不能为空！");
        }
        List<SystemMenuAllotDO> select = (List<SystemMenuAllotDO>) this.listByIds(list);
        if (ObjectValidators.isEmpty(select) || select.size() != list.size()) {
            throw getAppException("移除用户菜单失败！部分菜单分配数据不存在！");
        }
        // 鉴权，根据获取的分配数据获取到原始的用户，角色数据，判断是否支持修改
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        CacheStore cacheStore = null;
        if (cacheLoginUser.getType().equals(BusinessConstants.USER_TYPE_STORE)) {
            cacheStore = currentStoreCacheNotNull();
        }
        List<Integer> accountList = select.stream()
                .filter(item -> item.getAllotPart().equals(BusinessConstants.PERMISSION_ALLOT_PART_USER))
                .map(SystemMenuAllotDO::getPartId)
                .collect(Collectors.toList());
        List<Integer> roleIdList = select.stream()
                .filter(item -> item.getAllotPart().equals(BusinessConstants.PERMISSION_ALLOT_PART_ROLE))
                .map(SystemMenuAllotDO::getPartId)
                .collect(Collectors.toList());
        if (ObjectValidators.isNotEmpty(accountList)) {
            List<AccountDO> accountDoList = accountMapper.selectList(new LambdaQueryWrapper<AccountDO>()
                    .in(AccountDO::getAccount, accountList)
                    .eq(AccountDO::getUserType, cacheLoginUser.getType()));
            if (ObjectValidators.isEmpty(accountDoList) || accountDoList.size() != accountList.size()) {
                throw getAppException("移除用户菜单失败！需要移除菜单的部分用户不存在！");
            }
        }
        if (ObjectValidators.isNotEmpty(roleIdList)) {
            LambdaQueryWrapper<RoleDO> wrapper = new LambdaQueryWrapper<RoleDO>()
                    .in(RoleDO::getRoleId, roleIdList)
                    .eq(RoleDO::getManageType, cacheLoginUser.getType());
            if (ObjectValidators.isNotEmpty(cacheStore)) {
                wrapper.eq(RoleDO::getStoreId, cacheStore.getId());
            }
            List<RoleDO> roleDoList = roleMapper.selectList(wrapper);
            if (ObjectValidators.isEmpty(roleDoList) || roleDoList.size() != roleIdList.size()) {
                throw getAppException("移除用户菜单失败！需要移除菜单的部分角色不存在！");
            }
        }

        LocalDateTime localDateTime = LocalDateTime.now();
        this.update(new LambdaUpdateWrapper<SystemMenuAllotDO>()
                .set(SystemMenuAllotDO::getRemoveTime, localDateTime)
                .set(SystemMenuAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                .set(SystemMenuAllotDO::getRemoveUserName, cacheLoginUser.getName())
                .set(SystemMenuAllotDO::getRemoveTime, cacheLoginUser.getType())
                .set(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .eq(SystemMenuAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND)
                .eq(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_TRUE)
                .in(SystemMenuAllotDO::getId, list));
        return true;
    }
}
